﻿using System;
using System.Collections.Generic;
using FireStarter.Base;
using FireStarterModeller.BO;
using Habanero.Base;
using Habanero.Base.Exceptions;

namespace FireStarterModeller.Logic
{
    /// <summary>
    /// Creates a <see cref="UIGridFilter"/> amd its related <see cref="UIGridFilterProp"/>s based on the list of properties.
    /// </summary>
    public class UIGridFilterCreator
    {
        private readonly DMSolution _solution;

        public UIGridFilterCreator(DMSolution solution)
        {
            _solution = solution;
        }

        /// <summary>
        /// Creates a <see cref="UIGridInfo"/> with a <see cref="UIGridColumnInfo"/> for each property 
        /// in the collection of properties <paramref name="properties"/> except that a property marked as 
        /// an Object ID or a property marked as KeepValuePrivate will not be shown.
        /// </summary>
        /// <param name="properties"></param>
        /// <returns></returns>
        public UIGridFilter CreateUIGridFilter(IList<DMProperty> properties)
        {
            if (properties == null) throw new ArgumentNullException("properties");
            UIGridFilter gridFilter = new UIGridFilter();

            foreach (DMProperty property in properties)
            {
//                if (property.IsPartOfObjectIdentity) continue;
                gridFilter.UIGridFilterProps.Add(CreateFilterProp(property));
            }
            return gridFilter;
        }

        /// <summary>
        /// Creates a <see cref="UIGridInfo"/> with a <see cref="UIGridColumnInfo"/> using the property names given.
        /// </summary>
        /// <param name="propertyNames"></param>
        /// <returns></returns>
        public UIGridFilter CreateUIGridFilter(IEnumerable<string> propertyNames)
        {
            if (propertyNames == null) throw new ArgumentNullException("propertyNames");
            UIGridFilter gridFilter = new UIGridFilter();

            int ordinalPosition = 0;
            UITypeDefinition typeDefinition = UIGridFilterCreator.GetStringTextBoxFilterType(_solution);
            foreach (string propertyName in propertyNames)
            {
                gridFilter.UIGridFilterProps.Add(CreateFilterProp(propertyName, ordinalPosition++, typeDefinition));
            }
            return gridFilter;
        }



        /// <summary>
        /// Creates a <see cref="UIGridFilterProp"/> for the <see cref="DMProperty"/>.
        /// The Filter Prop is the property that defines a filter that is used to filter the grid
        /// based on the match to the <see cref="DMProperty"/> value.
        /// </summary>
        /// <param name="property"></param>
        /// <returns></returns>
        public UIGridFilterProp CreateFilterProp(DMProperty property)
        {
            if (property == null) throw new ArgumentNullException("property");
            ValidatePropertySetupCorrectly(property);
            string propertyName = property.PropertyName;
            UITypeDefinition typeDefinition = GetControlType(property);
            int? position = property.OrdinalPosition;
            UIGridFilterProp uiGridFilterProp = CreateFilterProp(propertyName, position, typeDefinition);
            uiGridFilterProp.LabelText = property.DisplayName;
            return uiGridFilterProp;
        }

        /// <summary>
        /// Creates a <see cref="UIGridFilterProp"/> for the name, ordinal position and type definition passed in.
        /// Creates a standard StringTextBoxFilter
        /// </summary>
        /// <returns></returns>
        public UIGridFilterProp CreateFilterProp(string propertyName, int? position, UITypeDefinition typeDefinition)
        {
            UIGridFilterProp filterProp = new UIGridFilterProp { PropertyName = propertyName };
            filterProp.OrdinalPosition = position;
            filterProp.UIGridFilterType = typeDefinition;
            filterProp.FilterClauseOp = GetFilterDefaultClauseOperator(filterProp.UIGridFilterType);
            return filterProp;
        }

        private static FilterClauseOperator? GetFilterDefaultClauseOperator(UITypeDefinition uiGridFilterType)
        {
            if (uiGridFilterType == null) throw new ArgumentNullException("uiGridFilterType");
            switch (uiGridFilterType.TypeName)
            {
                case "StringTextBoxFilter":
                    return FilterClauseOperator.OpLike;
                default:
                    return FilterClauseOperator.OpEquals;
            }
        }

        private static void ValidatePropertySetupCorrectly(DMProperty dmProperty)
        {

            if (dmProperty.Class == null)
            {
                throw new HabaneroArgumentException
                    ("property.Class",
                     "You cannot create a UIGridFilterProp for a property that is not associated with a class (Property '"
                     + dmProperty.PropertyName + "')");
            }
            if (dmProperty.Class.Solution == null)
            {
                throw new HabaneroArgumentException
                    ("property.Class.Solution",
                     "You cannot create a UIGridFilterProp for a property that is not associated with a Solution - (Property '"
                     + dmProperty.PropertyName + "')");
            }
            if (dmProperty.PropertyType == null)
            {
                throw new HabaneroArgumentException
                    ("property.PropertyType",
                     "You cannot create a UIGridFilterProp for a property that is not associated with a PropertyType - (Property '"
                     + dmProperty.PropertyName + "')");
            }
        }

        //Idea: This should be moved into some sort of a a mapper class? Brett 22 03 2009

        private static UITypeDefinition GetControlType(DMProperty property)
        {
            UITypeDefinition type;
            var solution = property.Class.Solution;
            if (property.HasLookupList)
            {
                type = GetStringComboBoxFilterType(solution);
            }
            else
            {
                switch (property.PropertyType.PropertyTypeName)
                {
                    case "Boolean":
                        type = GetBoolCheckBoxFilterType(solution);
                        break;
                    case "DateTime":
                        type = GetDateRangeComboBoxFilterType(solution);
                        break;
                    default:
                        type = GetStringTextBoxFilterType(solution);
                        break;
                }
            }
            if (type == null)
            {
                string errMessage = string.Format
                    ("The UITypeDefinition for the Grid Filter is being "
                     + "returned as null from the solution '{0}' for the Property '{1}' of type '{2}'. "
                     + "There appears to be an issue with setting up the Type Definitions for the "
                     + "solution on load or at startup. ", solution, property, property.PropertyType);
                throw new HabaneroDeveloperException(errMessage, errMessage);
            }
            return type;
        }

        private static UITypeDefinition GetDateRangeComboBoxFilterType(IDMSolution solution)
        {
            return GetControlTypeFromSolution(solution, BOBroker.GetMapperAssemblyName(), "DateRangeComboBoxFilter");
        }

        private static UITypeDefinition GetStringComboBoxFilterType(IDMSolution solution)
        {
            return GetControlTypeFromSolution(solution, BOBroker.GetMapperAssemblyName(), "StringComboBoxFilter");
        }

        private static UITypeDefinition GetBoolCheckBoxFilterType(IDMSolution solution)
        {
            return GetControlTypeFromSolution(solution, BOBroker.GetMapperAssemblyName(), "BoolCheckBoxFilter");
        }

        private static UITypeDefinition GetControlTypeFromSolution
            (IDMSolution solution, string assemblyName, string filterPropTypeName)
        {
            return ((DMSolution)solution).GetUIFilterControlType(assemblyName, filterPropTypeName);
        }

        private static UITypeDefinition GetStringTextBoxFilterType(IDMSolution solution)
        {
            return GetControlTypeFromSolution(solution, BOBroker.GetMapperAssemblyName(), "StringTextBoxFilter");
        }
    }
}